/********************************************
  hsrb_eval.c

  Copyright (c) 2008, Jin Nishikawa
********************************************/
#include <ruby.h>
#include <errno.h>
#include "hsrb_eval.h"

#define HSRB_STRING_COPY(val) do { \
    char* str = RSTRING_PTR(val); \
    int len = RSTRING_LEN(val); \
    if (str[len - 1] != 0x0) { \
      len += 1; \
    } \
    ret = cpy((void*) str, len); \
} while (0)

#define HSRB_FIXNUM_COPY(val) do { \
    int tmp = FIX2INT(val); \
    ret = cpy(&tmp, sizeof tmp); \
} while (0)

#define HSRB_FLOAT_COPY(val) do { \
    double tmp = NUM2DBL(val); \
    ret = cpy(&tmp, sizeof tmp); \
} while (0)

static int hsrb_ruby_init() {
  if (!ruby_initialized) {
    ruby_init();
    ruby_init_loadpath();
    ruby_initialized = 1;
  }
  return ruby_initialized;
}

static VALUE hsrb_ruby_eval(int* state, char* str) {
  hsrb_ruby_init();
  return rb_eval_string_protect(str, state);
}

void* cpy(void* src, int len) {
  void* ret = malloc(len);
  if (ret == NULL) {
    return NULL;
  }
  memset(ret, 0x0, len);
  memcpy(ret, src, len);
  return ret;
}

void* rb_eval(char* str, int* type) {
  VALUE val;
  int state = 0;
  void* ret = NULL;

  val = hsrb_ruby_eval(&state, str);
  errno = (state == 0) ? 0 : ((errno == 0) ? state : errno);
  if (errno == 0) {
    *type = TYPE(val);
  }
  switch (*type) {
    case T_STRING:
      HSRB_STRING_COPY(val);
      break;
    case T_FIXNUM:
      HSRB_FIXNUM_COPY(val);
      break;
    case T_BIGNUM:
      {
        VALUE tmp = rb_funcall(val,rb_intern("to_s"),0);
        HSRB_STRING_COPY(tmp);
      }
      break;
    case T_FLOAT:
      HSRB_FLOAT_COPY(val);
      break;
    case T_NIL: case T_TRUE: case T_FALSE:
      break;
    default:
      errno = EINVAL;
  }
  return ret;
}
